(ns clj-8583.bitmap
  (:import (java.nio.charset Charset)))

(defn- bits-in-range
  [low high bits]
  (filter #(and (> % low) (< % high)) bits))

(defn- flag-next-bitmap-set
  [this-bitmap bits-from-next-bitmap]
  (concat (when bits-from-next-bitmap [1]) this-bitmap))

(defn- long-to-bytes
  [number]
  (byte-array (map #(bit-and 0xFF (bit-shift-right number %)) (reverse (range 0 64 8)))))

(defn little-endian-bitmap
  [bit-sets]
  (long-to-bytes (reduce #(bit-or %1 %2) 0 (map #(bit-shift-left 1 (- 64 %)) bit-sets))))

(defn write-bitmap
  [bit-sets]
  (let [secondary-bitmap-bits
          (map #(- % 64) (bits-in-range 64 129 bit-sets))
        primary-bitmap-bits
          (flag-next-bitmap-set (bits-in-range 1 65 bit-sets) secondary-bitmap-bits)]
    (concat
      (little-endian-bitmap primary-bitmap-bits)
      (little-endian-bitmap secondary-bitmap-bits))))


(defmulti set-bits
  (fn [input] (if (instance? Iterable input) :iterable :single-byte)))

(defmethod set-bits
  :single-byte
  [byte]
  (keep-indexed #(if %2 %1) (map #(bit-test byte %) (range 0 8))))

(defmethod set-bits
  :iterable
  [bytes]
  (let [number-of-bytes (count bytes)
        offset-for (fn [index] (- (* (- number-of-bytes 1) 8) (* index 8)))]
    (-> (keep-indexed (fn [index item] (let [offset (offset-for index)] (map #(+ % offset) (set-bits item)))) bytes)
        flatten
sort)))

(defn little-endian-set-bits
  [bytes]
  (sort (map #(- (* 8 (count bytes)) %) (set-bits bytes))))


;(concat (little-endian-bitmap bit-sets) (little-endian-bitmap '(64)))
;1 2 3 4 7 11 12 13 22 25 26 32 33 37 41 42 43 48 49
